/*
 * Author: ahxgw
 * Created Time:  Thu 14 Apr 2011 10:59:46 PM PDT
 * Description: 
 */
#include "events.h"
#include "threadPool.h"
#include "utils.h"
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <string.h>
#include <pthread.h>
#include <mysql/mysql.h>
#include <errno.h>
#include <signal.h>

#define MaxConN 1024

int main(int argc, char *argv[])
{
    int i, on;
    int listenfd, connfd, sockfd;
    int port = SERV_PORT;
    int nfds;
    socklen_t clilen;
    SAI addr, remoteAddr;
    struct epoll_event ev, pev[MaxConN];
    char sql[BUF_SIZE];
    MYSQL_RES *res;
    MYSQL_ROW row;
    
    if (argc > 1)
        port = atoi(argv[1]);
    
    bzero(pev, sizeof(pev));
    bzero(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    clilen = sizeof(addr);
    
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd < 0)
        err_sys("create socket error");
    setNB(listenfd);
    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    if (bind(listenfd, (SA *) &addr, sizeof(addr)) == -1)
        err_sys("bind error");
    if (listen(listenfd, 100) == -1)
        err_sys("listen error");
    
    epfd = epoll_create(MaxConN);
    if (epfd == -1)
        err_sys("epoll create error");
    ev.events = EPOLLIN;
    ev.data.ptr = new Node(listenfd);
    if (epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev) < 0)
        err_sys("epoll ctl add error");

	pipe(pfd1);
	setNB(pfd1[1]);
	ev.events = EPOLLOUT;
	ev.data.ptr = new Node(pfd1[1]);
	if (epoll_ctl(epfd, EPOLL_CTL_ADD, pfd1[1], &ev) < 0)
		err_sys("epoll ctl add error");

	pipe(pfd2);
	setNB(pfd2[0]);
	ev.events = EPOLLIN;
	ev.data.ptr = new Node(pfd2[0]);
	if (epoll_ctl(epfd, EPOLL_CTL_ADD, pfd2[0], &ev) < 0)
		err_sys("epoll ctl add error");

	mysql_init(&mysql);
	if (!mysql_real_connect(&mysql, "localhost", "ahxgw", "nani", "ahxgw", 0, 0, 0))
        err_sys("mysql connect error");
    sprintf(sql, "select max(UID) from cus_table");
    mysql_query(&mysql, sql);
    res = mysql_store_result(&mysql);
    row = mysql_fetch_row(res);
    if (row[0])
    {
        sscanf(row[0], "%d", &UID);
        UID++;
    }
	
	threadPoolInit();
    
    signal(SIGALRM, sig_alrm);
    alarm(30);
    
    while (1)
    {
        nfds = epoll_wait(epfd, pev, MaxConN, -1);
        for (i = 0; i < nfds; i++)
        {
            Node *p = (Node *)pev[i].data.ptr;
            if (p->fd == listenfd)
            {
                connfd = accept(listenfd, (SA *) &remoteAddr, &clilen);
                if (connfd == -1)
                {
                    if (errno == EWOULDBLOCK || errno == EINTR || errno == ECONNABORTED)
                        continue;
                    err_sys("accept error");
                }
                if (connfd >= MaxConN)
                    err_sys("too many connect");
                setNB(connfd);
                ev.data.ptr = new Node(connfd);
                ev.events = EPOLLIN;
                if (epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev) == -1)
                    err_sys("epoll ctl add error");
            }
            else if (pev[i].events & EPOLLIN)
                do_in((Node *) pev[i].data.ptr);
            else if (pev[i].events & EPOLLOUT)
                do_out((Node *) pev[i].data.ptr);
            else if (pev[i].events & (EPOLLHUP | EPOLLERR))
            {
                if (epoll_ctl(epfd, EPOLL_CTL_DEL, p->fd, &ev) == -1)
                    err_sys("epoll ctl del error");
                close(p->fd);
            }
            else
                fprintf(stdout, "%d %d\n", pev[i].data.fd, pev[i].events);
        }
    }
    
    close(listenfd);
    
    return 0;
}
